<?php

namespace app\common\Auth;


use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\ValidationData;
use Lcobucci\JWT\Parser;

/**
 * @title 基于jwt 的权限认证
 * Class JwtAuth
 * @package app\common\Auth
 */
class JwtAuth
{
    /*单例模式*/
    static private $instance = null;

    /*私有属性，生成的token值*/
    private $token;

    /*私有属性，解码token值*/
    private $decodeToken;

    /**
     * @title 头信息
     * 发布者
     * 接受者
     * 识别码
     * 有效周期
     */
    private $iss = "PHP";
    private $aud = "App";
    private $ident = "LONGTEXT";
    private $effective_time = 60 * 60;

    /*加密信息*/
    private $uid;

    /*秘钥信息*/
    private $secret = "SECRET";


    public static function getInstance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /*私有化构造方法*/
    private function __construct()
    {
    }

    /*私有化克隆方法*/
    private function __clone()
    {
    }


    /**
     * @title 初始化UID
     * @param $uid
     */
    public function setUid($uid)
    {
        $this->uid = $uid;
    }

    /**
     * @title 获取token值
     */
    public function getToken()
    {
        $this->encode();
        return (string)$this->token;
    }

    /**
     * @title 设置token值
     * @param $token
     */
    public function setToken($token)
    {
        $this->token = (new Parser())->parse((string)$token);
        $this->decode();
    }

    /**
     * @title 编码token
     * @return \Lcobucci\JWT\Token
     */
    public function encode()
    {
        $signer = new Sha256();
        $time = time();
        $this->token = (new Builder())
            ->issuedBy($this->iss) //颁发者
            ->permittedFor($this->aud) // 接受者
            ->identifiedBy($this->ident, true) // 识别码
            ->issuedAt($time) // 颁发时间 (iat claim)
            ->canOnlyBeUsedAfter($time) //可用时间(nbf claim)
            ->expiresAt($time + $this->effective_time) //失效时间(exp claim)
            ->withClaim('uid', $this->uid) // 填充加密 "uid" // 填充加密 "uid"  多参数继续操作此方法
            ->getToken($signer, new Key($this->secret)); // 返回token 加密方式Sha256 秘钥：secrect
        return $this->token;
    }

    /**
     * @title 解密token值
     */
    public function decode()
    {
        $this->uid = $this->token->getClaim('uid');
    }

    /**
     * @title 获取用户的UID
     * @return mixed
     */
    public function getUid()
    {
        $this->decode();
        return $this->uid;
    }

    /**
     * @title 验证token是否过期
     */
    public function validate()
    {
        $data = new ValidationData();
        $data->setIssuer($this->iss);
        $data->setAudience($this->aud);
        $data->setId($this->ident);
        $data->setCurrentTime(time());
        return $this->token->validate($data);
    }

    /**
     * @title 验证token加密方式 以及秘钥
     * @return mixed
     */
    public function verify()
    {
        $signer = new Sha256();
        return $this->token->verify($signer, new Key($this->secret));
    }
}